﻿namespace Practices.IdentityProvider {
    using System;
    using System.Collections.Generic;
    using System.Security.Claims;
    using System.IdentityModel.Configuration;
    using System.IdentityModel.Metadata;
    using System.IdentityModel.Protocols.WSTrust;
    using System.IdentityModel.Tokens;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography.X509Certificates;
    using System.Web;
    using System.Xml;
    using System.Xml.Linq;

    public class ContosoSecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration {
        public ContosoSecurityTokenServiceConfiguration() {
            string signingCertificatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Constants.SigningCertificate);
            X509Certificate2 signingCertificate = new X509Certificate2(signingCertificatePath, Constants.SigningCertificatePassword, X509KeyStorageFlags.PersistKeySet);

            this.TokenIssuerName = Constants.IssuerName;            
            this.SigningCredentials = new X509SigningCredentials(signingCertificate);
            this.ServiceCertificate = signingCertificate;
            this.SecurityTokenService = typeof(ContosoSecurityTokenService);
        }

        public XElement GetFederationMetadata() {
            // metadata document 
            EntityDescriptor entity = new EntityDescriptor(new EntityId(Constants.IssuerName));
            SecurityTokenServiceDescriptor sts = new SecurityTokenServiceDescriptor();
            entity.RoleDescriptors.Add(sts);

            // signing key
            KeyDescriptor signingKey = new KeyDescriptor(this.SigningCredentials.SigningKeyIdentifier);
            signingKey.Use = KeyType.Signing;
            sts.Keys.Add(signingKey);

            // claim types
            sts.ClaimTypesOffered.Add(new DisplayClaim(ClaimTypes.Upn, "UPN", "User Principal Name"));

            // hostname
            var uri = HttpContext.Current.Request.Url;
            var host = string.Format("{0}://{1}", uri.Scheme, uri.Authority);

            EndpointReference activeEndpoint = new EndpointReference(host + Constants.WSTrustSTS);
            EndpointReference passiveEndpoint = new EndpointReference(host + Constants.WSFedStsIssue);

            // add the endpoints of the security token service
            sts.SecurityTokenServiceEndpoints.Add(activeEndpoint);
            // add the passive requestor endpoints
            sts.PassiveRequestorEndpoints.Add(passiveEndpoint);

            // supported protocols

            //Inaccessable due to protection level
            sts.ProtocolsSupported.Add(new Uri("http://docs.oasis-open.org/wsfed/federation/200706"));

            // metadata signing
            entity.SigningCredentials = this.SigningCredentials;

            // serialize 
            var serializer = new MetadataSerializer();
            XElement federationMetadata = null;

            using (var stream = new MemoryStream()) {
                serializer.WriteMetadata(stream, entity);
                stream.Flush();
                stream.Seek(0, SeekOrigin.Begin);

                XmlReaderSettings readerSettings = new XmlReaderSettings {
                    DtdProcessing = DtdProcessing.Prohibit, // prohibit DTD processing
                    XmlResolver = null, // disallow opening any external resources
                    // no need to do anything to limit the size of the input, given the input is crafted internally and it is of small size
                };

                XmlReader xmlReader = XmlTextReader.Create(stream, readerSettings);
                federationMetadata = XElement.Load(xmlReader);
            }

            return federationMetadata;
        }
    }
}